<template>
  <div class="game-container">
    <h1>开心消消乐</h1>
    <div class="game-stats">
      <p>得分: {{ score }}</p>
      <p>剩余步数: {{ moves }}</p>
    </div>
    <div class="grid" :style="{ gridTemplateColumns: `repeat(${boardSize}, 1fr)` }">
      <div
        v-for="(candy, index) in board"
        :key="`${index}-${candy.color}`"
        class="candy"
        :class="[
          `candy-${candy.color}`,
          { 
            selected: selectedCandy === index,
            matched: candy.isMatched,
            dropping: candy.isDropping
          }
        ]"
        :style="{
          transform: candy.isDropping ? `translateY(${candy.dropDistance}px)` : 'none',
          transition: `transform ${dropAnimationDuration}ms ease-in`
        }"
        @click="selectCandy(index)"
      >
        <div class="candy-inner"></div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';

interface Candy {
  color: number;
  isMatched: boolean;
  isDropping?: boolean;
  dropDistance?: number;
}

const boardSize = 8; // 8x8的网格
const colors = 6; // 6种颜色
const minMatch = 3; // 最少3个相同颜色才能消除
const moves = ref(30); // 初始步数
const score = ref(0);
const board = ref<Candy[]>([]);
const selectedCandy = ref<number | null>(null);
const dropAnimationDuration = 300; // 下落动画持续时间（毫秒）

// 检查位置是否会形成匹配
const willFormMatch = (items: Candy[], pos: number, color: number) => {
  const row = Math.floor(pos / boardSize);
  const col = pos % boardSize;

  // 检查水平方向
  if (col >= 2) {
    if (items[pos - 1]?.color === color && items[pos - 2]?.color === color) {
      return true;
    }
  }

  // 检查垂直方向
  if (row >= 2) {
    if (
      items[pos - boardSize]?.color === color &&
      items[pos - boardSize * 2]?.color === color
    ) {
      return true;
    }
  }

  return false;
};

// 修改初始化函数
const initializeBoard = () => {
  const items: Candy[] = [];
  
  // 逐个位置填充颜色，确保不会形成匹配
  for (let i = 0; i < boardSize * boardSize; i++) {
    let color: number;
    do {
      color = Math.floor(Math.random() * colors) + 1;
    } while (willFormMatch(items, i, color));

    items.push({
      color,
      isMatched: false,
      isDropping: false
    });
  }

  board.value = items;
  score.value = 0;
  moves.value = 30;
};

// 检查是否相邻
const isAdjacent = (index1: number, index2: number) => {
  const row1 = Math.floor(index1 / boardSize);
  const col1 = index1 % boardSize;
  const row2 = Math.floor(index2 / boardSize);
  const col2 = index2 % boardSize;

  return (
    (Math.abs(row1 - row2) === 1 && col1 === col2) ||
    (Math.abs(col1 - col2) === 1 && row1 === row2)
  );
};

// 交换糖果
const swapCandies = async (index1: number, index2: number) => {
  const candy1 = board.value[index1];
  const candy2 = board.value[index2];
  
  // 添加过渡类
  candy1.isDropping = true;
  candy2.isDropping = true;
  
  // 等待动画完成
  await new Promise(resolve => setTimeout(resolve, dropAnimationDuration));
  
  // 交换位置
  board.value[index1] = candy2;
  board.value[index2] = candy1;
  
  // 移除过渡类
  candy1.isDropping = false;
  candy2.isDropping = false;
};

// 检查是否有匹配
const checkMatches = () => {
  let hasMatches = false;
  // 检查行
  for (let row = 0; row < boardSize; row++) {
    for (let col = 0; col < boardSize - 2; col++) {
      const index = row * boardSize + col;
      const color = board.value[index].color;
      if (
        color === board.value[index + 1].color &&
        color === board.value[index + 2].color
      ) {
        board.value[index].isMatched = true;
        board.value[index + 1].isMatched = true;
        board.value[index + 2].isMatched = true;
        hasMatches = true;
      }
    }
  }
  // 检查列
  for (let col = 0; col < boardSize; col++) {
    for (let row = 0; row < boardSize - 2; row++) {
      const index = row * boardSize + col;
      const color = board.value[index].color;
      if (
        color === board.value[index + boardSize].color &&
        color === board.value[index + boardSize * 2].color
      ) {
        board.value[index].isMatched = true;
        board.value[index + boardSize].isMatched = true;
        board.value[index + boardSize * 2].isMatched = true;
        hasMatches = true;
      }
    }
  }
  return hasMatches;
};

// 消除匹配的糖果并填充新的
const removeMatches = async () => {
  let points = 0;
  board.value.forEach(candy => {
    if (candy.isMatched) {
      points += 10;
    }
  });
  score.value += points;

  // 先执行消除动画
  await new Promise(resolve => setTimeout(resolve, 300));

  // 计算每列需要下落的距离
  for (let col = 0; col < boardSize; col++) {
    let dropDistance = 0;
    for (let row = boardSize - 1; row >= 0; row--) {
      const index = row * boardSize + col;
      const candy = board.value[index];
      
      if (candy.isMatched) {
        dropDistance += 50; // 每个格子的高度
      } else if (dropDistance > 0) {
        candy.isDropping = true;
        candy.dropDistance = dropDistance;
      }
    }
  }

  // 等待下落动画完成
  await new Promise(resolve => setTimeout(resolve, dropAnimationDuration));

  // 更新棋盘状态
  for (let col = 0; col < boardSize; col++) {
    let writePos = boardSize - 1;
    for (let row = boardSize - 1; row >= 0; row--) {
      const index = row * boardSize + col;
      if (!board.value[index].isMatched) {
        if (writePos !== row) {
          board.value[writePos * boardSize + col] = {
            ...board.value[index],
            isDropping: false,
            dropDistance: 0
          };
        }
        writePos--;
      }
    }
    // 填充新的糖果
    for (let row = writePos; row >= 0; row--) {
      board.value[row * boardSize + col] = {
        color: Math.floor(Math.random() * colors) + 1,
        isMatched: false,
        isDropping: false
      };
    }
  }
};

// 选择糖果
const selectCandy = async (index: number) => {
  if (moves.value <= 0) return;

  if (selectedCandy.value === null) {
    selectedCandy.value = index;
  } else {
    if (isAdjacent(selectedCandy.value, index)) {
      await swapCandies(selectedCandy.value, index);
      if (checkMatches()) {
        moves.value--;
        await removeMatches();
        // 继续检查是否有新的匹配
        while (checkMatches()) {
          await new Promise(resolve => setTimeout(resolve, 300));
          await removeMatches();
        }
      } else {
        // 如果没有匹配，交换回来
        await swapCandies(selectedCandy.value, index);
      }
    }
    selectedCandy.value = null;
  }
};

onMounted(() => {
  initializeBoard();
});
</script>

<style scoped>
.game-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px;
}

.game-stats {
  display: flex;
  gap: 20px;
  margin-bottom: 20px;
  font-size: 1.2em;
  font-weight: bold;
}

.grid {
  display: grid;
  gap: 4px;
  padding: 10px;
  background: #f0f0f0;
  border-radius: 8px;
}

.candy {
  width: 50px;
  height: 50px;
  border-radius: 8px;
  cursor: pointer;
  position: relative;
  transition: transform 0.2s ease-out;
}

.candy.selected {
  transform: scale(0.9);
  z-index: 2;
}

.candy.matched .candy-inner {
  animation: match-animation 0.3s ease-out;
}

.candy-inner {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  transition: all 0.3s ease-out;
  position: relative;
}

.candy:hover .candy-inner {
  transform: scale(0.9);
}

@keyframes match-animation {
  0% {
    transform: scale(1);
    opacity: 1;
  }
  50% {
    transform: scale(1.2);
    opacity: 0.8;
  }
  100% {
    transform: scale(0);
    opacity: 0;
  }
}

/* 交换动画 */
.candy.selected .candy-inner {
  animation: pulse 0.5s infinite;
}

@keyframes pulse {
  0% { transform: scale(0.9); }
  50% { transform: scale(1); }
  100% { transform: scale(0.9); }
}

/* 下落动画 */
.candy.dropping .candy-inner {
  transition: transform 0.3s ease-in;
}

/* 颜色样式添加发光效果 */
.candy-1 .candy-inner { 
  background: #ff4444; 
  box-shadow: 0 0 10px #ff4444;
}
.candy-2 .candy-inner { 
  background: #44ff44;
  box-shadow: 0 0 10px #44ff44;
}
.candy-3 .candy-inner { 
  background: #4444ff;
  box-shadow: 0 0 10px #4444ff;
}
.candy-4 .candy-inner { 
  background: #ffff44;
  box-shadow: 0 0 10px #ffff44;
}
.candy-5 .candy-inner { 
  background: #ff44ff;
  box-shadow: 0 0 10px #ff44ff;
}
.candy-6 .candy-inner { 
  background: #44ffff;
  box-shadow: 0 0 10px #44ffff;
}
</style> 